﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Ganaye.EmbeddedDb
{
    public class QuickValueParser
    {
        private byte[] mBuffer;
        private int mCurrent, mTo;
        private byte mCurChar;

        internal void Init(byte[] buffer, int from, int to)
        {
            mBuffer = buffer;
            mCurrent = from;
            mTo = to;
            mCurChar = (mCurrent < to ? mBuffer[mCurrent] : (byte)0);
        }

        internal int? ParseNullableInt(char decimalSeparator)
        {
            int result = 0;
            SkipSpaces();
            bool negative = false;
            if (mCurChar == '-')
            {
                negative = true;
                NextChar();
            }
            if (mCurChar >= '0' && mCurChar <= '9')
            {
                while (mCurChar != 0 && mCurChar != decimalSeparator)
                {
                    // we ignore any comma or other characters
                    if (mCurChar >= '0' && mCurChar <= '9')
                    {
                        result = result * 10 + (mCurChar - '0');
                    }
                    NextChar();
                }
            }
            else return null;
            if (mCurChar == '-')
            {
                negative = true;
                NextChar();
            }
            return (negative ? -result : result);
        }

        internal double? ParseNullableDouble(char decimalSeparator)
        {
            double result = 0;
            SkipSpaces();
            bool negative = false;
            if (mCurChar == '-')
            {
                negative = true;
                NextChar();
            }
            if (mCurChar >= '0' && mCurChar <= '9')
            {
                while (mCurChar != 0 && mCurChar != decimalSeparator)
                {
                    // we ignore any comma or other characters
                    if (mCurChar >= '0' && mCurChar <= '9')
                    {
                        result = result * 10 + (mCurChar - '0');
                    }
                    NextChar();
                }
                if (mCurChar == decimalSeparator)
                {
                    NextChar();
                    double exp = 0.1;
                    while (mCurChar != 0 && mCurChar != decimalSeparator)
                    {
                        // we ignore any comma or other characters
                        if (mCurChar >= '0' && mCurChar <= '9')
                        {
                            result += exp * (mCurChar - '0');
                            exp /= 10;
                        }
                        NextChar();
                    }
                }
            }
            else return null;
            if (mCurChar == '-')
            {
                negative = true;
                NextChar();
            }
            return (negative ? -result : result);
        }


        private void NextChar()
        {
            mCurrent++;
            if (mCurrent>=mTo) mCurChar=0;
            else mCurChar=mBuffer[mCurrent];
        }


        private void SkipSpaces()
        {
            while (mCurChar == ' ')
            {
                NextChar();
            }
        }

        internal DateTime? ParseNullableDate()
        {
            int? value = ParseNullableInt('\0');
            // Using this for generating an index speeds it up by 50%. No checks added, assuming data is correct
            if (value.HasValue)
            {
                try
                {
                    int valueInt=value.Value;
                    int day = valueInt % 100;
                    int month = (valueInt / 100) % 100;
                    int year = (valueInt / 10000);
                    return new DateTime(year, month, day);
                }
                catch (Exception)
                { // will return null;
                }
            }
            return null;
        }

        internal bool? ParseNullableBool()
        {
            switch (mCurChar)
            {
                case (byte)'Y':
                case (byte)'T':
                case 1:
                    return true;

                case (byte)'N':
                case (byte)'F':
                case 0: 
                    return false;

                case (byte)' ':
                    return null;

                default: 
                    return null;
            }
        }

    }
}
